Skip to content

Java: add experimental java/ldap-dn-injection-library-mode query#22003

Open
tonghuaroot wants to merge 1 commit into
github:mainfrom
tonghuaroot:ldap-dn-injection-libmode-experimental
Open

Java: add experimental java/ldap-dn-injection-library-mode query#22003
tonghuaroot wants to merge 1 commit into
github:mainfrom
tonghuaroot:ldap-dn-injection-libmode-experimental

Conversation

@tonghuaroot

Copy link
Copy Markdown
Contributor

What

A new experimental query, java/ldap-dn-injection-library-mode, that detects LDAP
distinguished-name injection (CWE-90, RFC 2253) into a bind DN inside an
authentication library or framework (Apache Shiro, a custom Spring Security realm,
a CAS / pac4j SPI, a Keycloak provider).

Why the supported query misses this

java/ldap-injection starts from ActiveThreatModelSource (remote flow sources). An
auth framework has none — the login principal arrives as a method parameter, not
as a servlet parameter or request body. On a framework database the supported query
therefore has zero sources, regardless of the sink model. This query closes that
source-boundary gap with library-boundary sources.

Sources (library-boundary)

  • Login-principal accessors: Shiro AuthenticationToken.getPrincipal /
    getUsername, Spring Security Authentication.getName / getPrincipal,
    java.security.Principal.getName.
  • DN-builder method parameters: a String parameter of a method whose name looks
    like a DN builder (getUserDn, *UserDn, buildDn, resolveDn,
    getUsernameWithSuffix, get*Principal, ...).

Honest caveat — the DN-builder source model is name-heuristic. It keys partly off
method names. This is a deliberate precision/recall trade for the library case where
there is no remote flow source to anchor on: a framework that builds the DN in a
differently named helper is missed, and a benign method that matches the name pattern
may produce a false positive. This is why the query is experimental and
@precision medium, and the trade-off is documented in both the QLDoc and the qhelp.
Triage a result by confirming the value reaches a real bind sink unescaped.

Sinks (bind DN)

javax.naming Context / DirContext bind / rebind / lookup / lookupLink /
createSubcontext (the String name argument); the java.naming.security.principal
environment value; and Shiro LdapContextFactory.getLdapContext (the principal
argument). new LdapName(String) is deliberately excluded (it commonly parses an
existing cert/principal DN, not a fresh one for a bind). Barriers are RFC 2253 DN
escapers (Rdn.escapeValue, Spring LdapEncoder.nameEncode, ESAPI encodeForDN).

The query defines its sinks inline rather than reusing the supported
LdapInjectionSink library, so it stands alone and does not depend on the companion
bind-DN-sinks PR being merged first.

Evidence (Apache Shiro CVE-2026-49268)

CVE-2026-49268 (fixed 2.2.1 / 3.0.0-alpha-2). Built a database from
apache/shiro@shiro-root-2.2.0 and ran a 3-way comparison:

Query Hits on Shiro 2.2.0
stock java/ldap-injection 0 (search-only sinks)
java/ldap-injection + bind-DN sinks (companion PR) 0 (no remote flow source in a library)
java/ldap-dn-injection-library-mode (this PR) 8

The 8 results land on exactly the patched code: DefaultLdapRealm.getUserDn /
getLdapContext(principal, ...) and ActiveDirectoryRealm.getUsernameWithSuffix, with
the source correctly traced to AuthenticationToken.getUsername() / getPrincipal().
This satisfies the experimental-query requirement of at least one true positive on a
real project.

Tests / help

Ships a qhelp (with bad/good samples) and a true-positive / true-negative test shaped
like the Shiro realm (getUserDn concatenation vs Rdn.escapeValue), plus the Shiro
stubs the test needs. codeql test run is green and the query compiles with
--warnings=error.

The supported java/ldap-injection query starts from remote flow sources, so
it does not report on authentication frameworks, where the login principal
arrives as a method parameter rather than at a servlet parameter or similar.
This experimental query detects LDAP distinguished-name injection (CWE-90,
RFC 2253) into a bind DN inside such a framework.

Sources are library-boundary values: login-principal accessors of common auth
frameworks (Apache Shiro AuthenticationToken, Spring Security Authentication,
java.security.Principal) and the string parameters of DN-builder-shaped
methods. The DN-builder source model is name-heuristic, a deliberate
precision/recall trade for the library case where there is no remote flow
source to anchor on; the query is therefore experimental and medium precision.

Sinks are the bind-DN positions: javax.naming Context / DirContext bind,
rebind, lookup, lookupLink, createSubcontext; the java.naming.security.principal
environment value; and Apache Shiro LdapContextFactory.getLdapContext. Barriers
are RFC 2253 DN escapers such as Rdn.escapeValue. Anchored on Apache Shiro
CVE-2026-49268.

Adds a qhelp, a true-positive/true-negative test, and the Shiro stubs the test
needs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant